/* This file declares the functions used to get and put characters to the UART (tty) */

#ifndef UART_H
#define UART_H

#define UNUSED 0
#define PRINTING 1
#define READING 2

#include "process_management.h"
#include "malta.h"
#include "pcb_fifo_queue.h"

#define INTERNAL_QUEUE_LENGTH 10


/* internal queue type declaration. It's a FIFO queue that is used to implement some functionalities (like backspace) */

typedef struct{
  char queue[INTERNAL_QUEUE_LENGTH];
  int32_t count;
  int32_t in;
  int32_t out;
}internal_queue_t;

/* functions to manipulate the internal queue */

/* puts the character c in the internal queue. Returns 0 if the queue is full, 1 otherwise. */
int32_t internal_queue_put(char c);

/* gets the first character in the internal queue, copies it in c and removes it from the queue. Returns 0 if the queue is empty, 1 otherwise. */
int32_t internal_queue_get(char* c);

/* resets the internal queue */
void reset_internal_queue();

/* functions to manipulate the UART */

/* configures the UART */
void configure_uart();

/* cleans the uart's receiving buffer of any data that might be left in it */
void clean_uart();

/* sets the global variables with the correct values to print data */
void set_printing_mode(const char* data);

/* sets the global variables with the correct values to get input from the user and store it into data (up to length-1 characters) */
void set_reading_mode(char* data, int32_t length);

/* function called by the exception handler in case of tty0 originating exceptions */
void uart_handler();

/* pcb tries to become the UART's owner. If it is not possible, it is placed into the UART's FIFO queue . Returns 1 if pcb is now the owner of the device, 0 if it is blocked in the queue and -1 in case of fatal error.*/
int32_t get_uart(PCB* pcb);

/* releases the UART and the new owner is the first process blocked in the queue. Both the old and new owners are waken up by this function. Returns 1 in case of success, 0 if it is impossible to wake the old owner up and -1 if wake_up fails on the new owner.  */
int32_t release_uart();

/* removes PCB from the fifo queye */
int32_t remove_uart_queue(PCB* pcb);

/* tries to get a character from the UART. Waits for one if none is available. Stops when the character entered is \r or when in_buffer_length - 1 characters have been read, whichever comes first. */ 
void read();

/* prints a character from out_buffer and sets the device to interrupt when it is done printing (only if there are remaining characters to print) */ 
void print();

/* ends the current use of the device and returns an error code that the owner */
int32_t end_of_io();

/* ends the use of the device by its current owner by waking it up. It also release the device and put the return code in the PCB. */
int32_t end_of_printing(int32_t code);

/* this function is exactly like end_of_printing except that it adds also a \0 character at the end of input */
int32_t end_of_reading(int32_t code);

#endif
